/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.jgrasstools.hortonmachine.oms;

import groovy.lang.Binding;
import groovy.lang.GroovyClassLoader;
import groovy.lang.GroovyShell;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Command Line interface to run simulations.
 *
 * @author od
 */
@SuppressWarnings("nls")
public class CLI {

    static {
        if (System.getProperty("java.version").compareTo("1.6") < 0) {
            throw new RuntimeException("Java 1.6+ required.");
        }
    }

    private CLI() {
    }

    /**
     * Executes a simulation.
     * 
     * @param file the file to execute
     * @param ll the log level
     * @param cmd the command to call (e.g. run)
     * @throws Exception
     */
    public static Object sim( String file, String ll, String cmd ) throws Exception {
        String f = CLI.readFile(file);
        Object o = CLI.createSim(f, false, ll);
        return CLI.invoke(o, cmd);
    }

    /**
     * Executed plain groovy.
     * 
     * @param file the groovy file
     * @param ll the log level.
     * @param cmd
     * @throws Exception
     */
    public static void groovy( String file, String ll, String cmd ) throws Exception {
        String f = CLI.readFile(file);
        Object o = CLI.createSim(f, true, ll);
    }

    /**
     * Invokes a simulation method. (run | doc | analysis | ...)
     * 
     * @param target the target simulation object
     * @param name the name of the method (eg. run())
     * @throws Exception
     */
    public static Object invoke( Object target, String name ) throws Exception {
        return target.getClass().getMethod(name).invoke(target);
    }

    /**
     * Read a file and provide its content as String.
     * 
     * @param name the file name
     * @return the content as String
     * @throws IOException something bad happened.
     */
    public static String readFile( String name ) throws IOException {
        StringBuilder b = new StringBuilder();
        BufferedReader r = new BufferedReader(new FileReader(name));
        String line;
        while( (line = r.readLine()) != null ) {
            b.append(line).append('\n');
        }
        r.close();
        return b.toString();
    }

    /**
     * Create a simulation object.
     * 
     * @param script the script 
     * @param groovy
     * @param ll
     * @return the simulation object.
     */
    public static Object createSim( String script, boolean groovy, String ll ) throws Exception {
        setOMSProperties();
        Level.parse(ll); // may throw IAE
        StringBuilder sb = new StringBuilder();
        sb.append("import static oms3.SimConst.*\n");
        sb.append("import java.util.*\n");
        sb.append("import oms3.SimBuilder\n");
        // sb.append("import org.jgrasstools.gears.libs.monitor.*\n");
        // sb.append("org.jgrasstools.gears.libs.monitor.IJGTProgressMonitor pm = (org.jgrasstools.gears.libs.monitor.IJGTProgressMonitor) new PrintStreamProgressMonitor(System.out, System.err);\n");
        sb.append("def sb = new SimBuilder(logging:'" + ll + "');\n");

        String prefix = groovy ? "" : sb.toString();
        // String prefix = groovy ? "" : "import static oms3.SimConst.*\n" +
        // "def __sb__ = new oms3.SimBuilder(logging:'" + ll
        // + "')\n" + "__sb__.";
        ClassLoader parent = Thread.currentThread().getContextClassLoader();
        GroovyShell shell = new GroovyShell(new GroovyClassLoader(parent), new Binding());
        return shell.evaluate(prefix + script);
    }

    // private

    private static void setOMSProperties() {
        String oms_work = System.getProperty("oms3.work");
        if (oms_work != null) {
            System.setProperty("oms3.prj", oms_work);
            String jna = System.getProperty("jna.library.path");
            if (jna != null) {
                jna = jna + File.pathSeparator + new File(oms_work, "dist").toString();
            } else {
                jna = new File(oms_work, "dist").toString();
            }
            System.setProperty("jna.library.path", jna);
        }
        System.setProperty("oms3.version", "3-SNAPSHOT");
        System.setProperty("oms3.home", System.getProperty("user.home") + File.separator + ".oms3" + File.separator
                + "3-SNAPSHOT");
    }

    private static void usage() {
        System.err.println("usage: java -jar oms-all.jar [-l <loglevel> ] [-r|-e|-d|-a|-s|-o] <simfile>");
        System.err.println(" Command line access to simulations.");
        System.err.println("           -r   run the <simfile>");
        System.err.println("           -e   edit parameter in <simfile>");
        System.err.println("           -o   open the last output folder in desktop <simfile>");
        System.err.println("           -d   document the <simfile>");
        System.err.println("           -a   run the <simfile> analysis");
        System.err.println("           -s   create SHA <simfile> digest");
        System.err.println("           -l <loglevel> set the log level:");
        System.err.println("                OFF|ALL|SEVERE|WARNING|INFO|CONFIG|FINE|FINER|FINEST");
    }

    public static void main( String[] args ) {
        String ll = "WARNING";
        try {
            for( int i = 0; i < args.length; i++ ) {
                if (args[i].equals("-r")) {
                    boolean isgroovy = args[++i].endsWith("groovy");
                    Logger log = Logger.getLogger("oms3.sim");
                    log.setLevel(Level.parse(ll));
                    Object target = createSim(readFile(args[i]), isgroovy, ll);
                    if (!isgroovy) {
                        invoke(target, "run");
                    }
                } else if (args[i].equals("-e")) {
                    Object target = createSim(readFile(args[++i]), false, ll);
                    invoke(target, "edit");
                } else if (args[i].equals("-d")) {
                    Object target = createSim(readFile(args[++i]), false, ll);
                    invoke(target, "doc");
                } else if (args[i].equals("-o")) {
                    Object target = createSim(readFile(args[++i]), false, ll);
                    invoke(target, "output");
                } else if (args[i].equals("-a")) {
                    Object target = createSim(readFile(args[++i]), false, ll);
                    invoke(target, "graph");
                } else if (args[i].equals("-s")) {
                    Object target = createSim(readFile(args[++i]), false, ll);
                    invoke(target, "dig");
                } else if (args[i].equals("-l")) {
                    ll = args[++i];
                } else if (args[i].endsWith("groovy")) {
                    createSim(readFile(args[i]), true, ll);
                } else {
                    usage();
                    return;
                }
            }
        } catch (Exception E) {
            E.printStackTrace(System.out);
            System.exit(1);
        }
    }
}
